專業理論深解:
SSRF (Server-Side Request Forgery):
漏洞本質: 攻擊者利用一個存在漏洞的 Web 應用,作為代理來發起對其他伺服器的請求。由於請求是從受信任的伺服器發出的,它可以繞過防火牆規則,訪問內部網路資源。
**攻擊場景:**常見於需要從遠端 URL 獲取資源的功能,如「從 URL 上傳圖片」、「WebHook 推送」、「檔案處理服務」等。
關鍵攻擊目標:
本地主機 (localhost/127.0.0.1): 訪問伺服器本地運行的、未對外開放的管理服務(如 Redis, Elasticsearch)。
雲服務元數據 (Metadata): 在雲環境中,攻擊 http://169.254.169.254/ 可以竊取到實例的臨時存取憑證 (IAM role credentials),這是極高風險的攻擊。
內部網路掃描: 透過枚舉內部 IP 地址和埠號,探測企業內網拓撲。
防禦策略: 建立一個基於白名單的允許訪問列表;禁止重定向;統一出口 IP,並在網路層進行訪問控制。
不安全的反序列化 (Insecure Deserialization):
核心概念: 「序列化」是將一個運行時的物件狀態轉換為可儲存/傳輸的格式(如字串、位元組流)。「反序列化」是其逆過程。
漏洞成因: 如果一個應用程式反序列化了來自不受信任來源的數據,攻擊者可以構造一個惡意的序列化物件。在反序列化過程中,應用程式會實例化這個物件,並可能自動觸發其某些方法(如 __wakeup() in PHP, readObject() in Java)。
屬性導向程式設計 (POP - Property-Oriented Programming): 攻擊者不需要注入新程式碼,而是利用應用程式現有程式碼中的「小工具」(Gadgets)——即那些在反序列化過程中會被呼叫並能執行危險操作的類和方法。攻擊者將這些 Gadgets 串連成一條「POP 鏈」,最終達到任意檔案讀寫、命令執行等效果。
一、核心本質:濫用伺服器的信任邊界
SSRF 的本質是攻擊者利用應用程式的一個功能缺陷,強迫 (Forge) 伺服器端 (Server-Side) 發起一個非預期的網路請求 (Request)。
關鍵在於,這個請求是從應用程式伺服器本身的網路介面發出的。這意味著:
來源 IP 的偽裝: 請求的來源 IP 是受信任的伺服器 IP,而不是攻擊者的 IP。
信任邊界的跨越: 伺服器通常位於防火牆之後,能夠訪問內部網路、本地主機 (localhost) 以及特殊的雲端元數據服務。這些是攻擊者從外部無法直接觸及的區域。SSRF 就像是攻擊者在伺服器內部安插了一個代理,使其能夠「隔山打牛」。
二、漏洞的根源:不可信的 URL 輸入
SSRF 漏洞通常出現在任何需要處理用戶提供的 URL 或能被用戶影響的 URL 的功能中。常見的場景包括:
從 URL 導入/抓取資源:
Webhook 推送(例如:GitLab, Slack aAPIs)。
從 URL 上傳圖片或檔案。
PDF/圖片生成器,需要渲染遠端網頁。
XML 解析器,處理外部實體 (XXE) 時可能觸發。
連結預覽生成: 社交媒體或通訊軟體中,貼上連結後自動生成標題和縮圖的功能。
內部 API 聚合器: 某些微服務架構中,一個服務需要根據參數去請求另一個內部服務。
一個極簡的漏洞程式碼範例如下 (Python):
Python
from flask import request
import requests
@app.route('/fetch_image')
def fetch_image():
image_url = request.args.get('url')
# 伺服器直接請求了用戶提供的 URL,沒有任何驗證
image_data = requests.get(image_url).content
return image_data
三、攻擊向量與高價值目標 (Impact Analysis)
SSRF 的威力不在於請求本身,而在於它能請求什麼。
內部網路偵察 (Internal Network Reconnaissance):
攻擊者可以將 URL 設為內部 IP 地址段(如 http://192.168.1.1、http://10.0.0.5:8080),並根據伺服器的回應時間、錯誤訊息或返回內容,來判斷內部主機和埠號是否開放。這相當於在企業內網進行了一次埠號掃描,繪製出內部網路拓撲。
訪問本地主機服務 (Accessing localhost):
許多服務(如 Redis, Elasticsearch, 監控儀表板)為了安全,預設只監聽在 127.0.0.1。攻擊者可透過 SSRF 提交 http://127.0.0.1:6379(Redis)或 http://localhost:9200(Elasticsearch),直接與這些未經嚴格認證的內部服務互動,進行數據竊取或執行未授權命令。
繞過存取控制列表 (ACL Bypass):
某些管理功能或內部 API 可能基於來源 IP 設置了存取控制,只允許來自本地或特定內部網段的請求。SSRF 發出的請求天然地繞過了這層防護。
竊取雲端服務元數據 (THE CROWN JEWEL):
這是 SSRF 在現代雲端環境中最致命的利用方式。AWS, GCP, Azure 等雲端供應商都提供一個特殊的本地 IP 地址,稱為「元數據服務 (Metadata Service)」,虛擬機可以透過訪問它來獲取自身的資訊。
AWS: http://169.254.169.254/latest/meta-data/
GCP: http://169.254.169.254/computeMetadata/v1/ (需要 Metadata-Flavor: Google 標頭)
Azure: http://169.254.169.254/metadata/instance
攻擊者可以提交上述 URL,竊取與該虛擬機實例關聯的臨時安全憑證 (IAM Role Temporary Credentials)。一旦獲取這些 AccessKeyId, SecretAccessKey, 和 Token,攻擊者就等於擁有了一個合法的身份,可以透過 AWS/GCP API 接管該實例、讀寫 S3 儲存桶、甚至橫向移動到雲端帳戶的其他部分,造成毀滅性打擊。
四、SSRF 的類型:基本型 vs. 盲注型
基本 SSRF (Basic SSRF):
伺服器會將請求遠端資源後的回應內容,完整或部分地返回給攻擊者。攻擊者可以得到直接的回饋,例如看到內部網頁的原始碼或 API 的 JSON 回應。利用起來相對直接。
盲注 SSRF (Blind SSRF):
伺服器發起了請求,但不會將任何回應內容返回給攻擊者。攻擊者無法直接看到結果。
驗證方法:
帶外交互 (Out-of-Band Interaction): 攻擊者讓伺服器請求一個由自己控制的伺服器地址(例如 Burp Collaborator 或自建的 DNS/HTTP 伺服器)。如果攻擊者的伺服器收到了來自目標伺服器的 DNS 查詢或 HTTP 請求,就證實了漏洞的存在。
時序分析 (Timing Analysis): 攻擊者可以請求一個已知回應緩慢或超時的地址。如果應用程式的回應時間明顯變長,則間接證明請求已發出。
五、繞過技術與防禦思想 (Evasion vs. Defense)
防禦 SSRF 的難點在於攻擊者會用各種技巧繞過不完善的過濾器。
攻擊者的繞過技巧:
黑名單繞過:
IP 格式轉換: 過濾 127.0.0.1?嘗試 2130706433 (十進制), 0177.0.0.1 (八進制), [::] (IPv6)。
使用域名: localhost, localhost.localdomain 等域名最終都指向 127.0.0.1。
URL 協議濫用: 除了 http(s)://,還可嘗試 file:///etc/passwd, dict://, gopher:// 等協議。gopher:// 協議極其危險,因為它允許構造任意 TCP 數據流,可以用來攻擊 Redis, SMTP 等服務。
DNS 重新綁定 (DNS Rebinding): 攻擊者設置一個 DNS 伺服器。當應用程式的防護機制第一次解析域名時,返回一個合法的公網 IP。當應用程式的後端 HTTP 客戶端第二次解析並發起實際請求時,DNS TTL 已過期,此時返回一個惡意的內部 IP(如 127.0.0.1)。
開放重定向 (Open Redirect): 利用目標信任的另一個網站上的開放重定向漏洞,將請求跳轉到內部地址。
防禦者的縱深防禦策略:
首選策略 - IP 白名單: 最強大的防禦。維護一份嚴格的白名單,只允許應用程式請求預先批准的、已知的、安全的 IP 地址或域名。預設拒絕所有其他請求。
統一請求出口: 在架構層面,應將所有需要對外發起請求的邏輯,收斂到一個統一的、經過安全加固的代理服務或函式庫中。禁止開發人員在業務程式碼中隨意呼叫 HTTP 客戶端。
禁用不必要的協議: 配置底層的 HTTP 客戶端,明確禁用除 HTTP 和 HTTPS 之外的所有協議。
網路層隔離: 作為最後一道防線,使用防火牆規則(如 AWS 的 Security Groups)限制伺服器實例的出站流量。禁止它訪問不必要的內部服務,特別是應阻止其訪問雲端元數據服務地址 (169.254.169.254),除非業務上確實需要。
啟用雲端安全增強功能: 例如,在 AWS 中強制使用 IMDSv2 (Instance Metadata Service Version 2)。IMDSv2 引入了基於會話的認證,要求先發送一個 PUT 請求獲取一個臨時 Token,再將此 Token 放入標頭中發起 GET 請求。這使得傳統的、單一請求的 SSRF 攻擊無法直接竊取憑證。